package models

import (
	"3rd/errors"
	"github.com/astaxie/beego/validation"
	goerrors "github.com/go-errors/errors"
	"uc/app/db"
	"database/sql"
)

type User struct {
	Qid       string `json:"qid"`
	AvatarUrl string `json:"avatarUrl" `
	UserName  string `json:"name" valid:"Required"`
	Email     string `json:"email"`
	Mobile    string `json:"mobile"`
	Company   string `json:"company"`
	RealName  string `json:"realName"`
	TelePhone string `json:"telePhone"`
	Password  string `json:"password" valid:"Required"`
	mediaType string
	Created   int64 `json:"created"`
}

func (this *User) Register() error {
	// whether the user had registered
	if err := this.MediaExists(); err != nil {
		return goerrors.New(err)
	} else {
		// register
		db, err := db.GetMysqlPool()
		if err != nil {
			return goerrors.New(err)
		}
		if _, err := db.Exec("insert into user (`username`, `email`, `password`, `qid`, `created`) VALUES( ?, ? , ?, ?, ?)",
			this.UserName, this.Email, this.Password, this.Qid, this.Created); err != nil {
			return goerrors.New(err)
		}
	}
	return nil
}

func (this *User) MediaExists() error {
	db, err := db.GetMysqlPool()
	if err != nil {
		return goerrors.New(err)
	}
	var rst int
	if this.Mobile != "" {
		err = db.QueryRow("select 1 from user where mobilePhone1 = ? or mobilePhone2 = ? or username = ?  limit 1",
			this.Mobile, this.Mobile, this.Mobile).Scan(&rst)
	} else if this.Email != "" {
		err = db.QueryRow("select 1 from user where email = ? or username = ?  limit 1",
			this.Email, this.Email).Scan(&rst)
	}
	if err != nil || rst == 0 {
		// does not exists
		return nil
	} else {
		return errors.New(MediaExists, "has already registered")
	}
}

func (this *User) UserNameExists() error {
	db, err := db.GetMysqlPool()
	if err != nil {
		return goerrors.New(err)
	}
	var rst int
	if err := db.QueryRow("select 1 from user where username = ?  limit 1", this.UserName).Scan(&rst); err != nil {
		// doesnot exists
		return nil
	} else {
		return errors.New(UserNameExists, "has already registered")
	}
}

func (this *User) UserExists(user string) error {
	db, err := db.GetMysqlPool()
	if err != nil {
		return goerrors.New(err)
	}
	var rst int
	if err := db.QueryRow("select 1 from user where username = ? or mobilePhone1 = ? or mobilePhone2 = ? or email = ?  limit 1",
		user, user, user, user).Scan(&rst); err != nil {
		// doesnot exists
		return nil
	} else {
		return errors.New(UserNameExists, "has already registered")
	}
}

func (this *User) ResetPwd(newPwd string) error {
		var (
		err error
		res sql.Result
	)
	db, err := db.GetMysqlPool()
	if err != nil {
		return goerrors.New(err)
	}
	if this.Mobile != "" {
		res, err = db.Exec("UPDATE user SET password = ? WHERE mobilePhone1 = ? or mobilePhone2 = ?", 
		newPwd, this.Mobile, this.Mobile)
	} else if this.Email != "" {
		db.Exec("UPDATE user SET password = ? WHERE email = ?", newPwd, this.Email)
	}
	if err != nil {
		return goerrors.New(err)
	}
	num, err := res.RowsAffected()
			if err != nil {
				return goerrors.New(err)
			}
			if num < 1 {
				return errors.New(InvalidUser, "invalid user")
			}

		return nil
}

func (this *User) ModifyPwd(newPwd string) error {
	db, err := db.GetMysqlPool()
	if err != nil {
		return goerrors.New(err)
	}
		if res, err := db.Exec("UPDATE user SET password = ? WHERE qid = ? && password = ?",
		 newPwd, this.Qid, this.Password); err != nil {
			return goerrors.New(err)
		} else {
			num, err := res.RowsAffected()
			if err != nil {
				return goerrors.New(err)
			}
			if num < 1 {
				return errors.New(InvalidPwd, "invalid pwd or qid")
			}
		}
		return nil
}

func (this *User) GetQidByName() (qid string, err error) {
	db, err := db.GetMysqlPool()
	if err != nil {
		return "", goerrors.New(err)
	}
	if err = db.QueryRow("select qid from user where username = ? and password = ?  limit 1", this.UserName, this.Password).Scan(&qid); err != nil {
		// doesnot exists
		return "", errors.New(InvalidPwd, "invalid usr or pwd")
	}
	return
}

func (this *User) ResolveMedia(media string) error {
	mediaType := (&Media{Media: media}).ResolveMediaType()

	if mediaType == Mobile {
		this.Mobile = media
	} else if mediaType == Mail {
		this.Email = media
	} else {
		return errors.New(UnknownMedia, "media must be provided")
	}
	return nil
}

type QS struct {
	Qid string `json:"qid" valid:"Required"`
	Sid string `json:"sid" valid:"Required"`
}

func (this *QS) Valid(v *validation.Validation) {
	// TODO:
	//v.SetError("media", "Unknown media type")
}
